{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pickle\n",
    "import logging\n",
    "import time\n",
    "from sklearn.ensemble import StackingClassifier, VotingClassifier, RandomForestClassifier, AdaBoostClassifier, GradientBoostingClassifier\n",
    "from sklearn.linear_model import LogisticRegression\n",
    "from sklearn.svm import SVC\n",
    "from sklearn.tree import DecisionTreeClassifier\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "from sklearn.metrics import accuracy_score\n",
    "from sklearn.model_selection import train_test_split\n",
    "from util import createXY  # 假设在当前路径下有util.py文件，其中包含createXY函数\n",
    "\n",
    "# 配置日志\n",
    "logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:24:16,669 - INFO - X和y已经存在，直接读取\n",
      "2024-10-31 19:24:16,670 - INFO - X文件大小:25.23MB\n",
      "2024-10-31 19:24:16,671 - INFO - y文件大小:0.05MB\n",
      "2024-10-31 19:24:16,746 - INFO - 训练集大小: (18750, 1024), 测试集大小: (6250, 1024)\n",
      "2024-10-31 19:24:16,747 - INFO - X文件大小: 18.31055 MB\n",
      "2024-10-31 19:24:16,747 - INFO - y文件大小: 0.07153 MB\n"
     ]
    }
   ],
   "source": [
    "# 定义用于加载和划分数据的函数\n",
    "def load_data():\n",
    "    X, y = createXY(train_folder=\"../data/train\", dest_folder=\".\", method=\"flat\")\n",
    "    X = np.array(X)\n",
    "    y = np.array(y)\n",
    "    return train_test_split(X, y, test_size=0.25, random_state=2023)\n",
    "\n",
    "# 载入数据，检查形状\n",
    "X_train, X_test, y_train, y_test = load_data()\n",
    "logging.info(f\"训练集大小: {X_train.shape}, 测试集大小: {X_test.shape}\")\n",
    "logging.info(f\"X文件大小: {X_train.nbytes / 1024**2:.5f} MB\")\n",
    "logging.info(f\"y文件大小: {y_train.nbytes / 1024**2:.5f} MB\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义训练和评估函数\n",
    "def train_and_evaluate(model, name):\n",
    "    start_time = time.time()\n",
    "    model.fit(X_train, y_train)\n",
    "    train_time = time.time() - start_time\n",
    "    logging.info(f\"{name}模型训练完成。用时{train_time:.4f}秒。\")\n",
    "    \n",
    "    start_time = time.time()\n",
    "    predictions = model.predict(X_test)\n",
    "    eval_time = time.time() - start_time\n",
    "    accuracy = accuracy_score(y_test, predictions)\n",
    "    logging.info(f\"{name}模型评估完成。用时{eval_time:.4f}秒。\")\n",
    "    logging.info(f\"{name}模型准确率: {accuracy:.4f}\")\n",
    "    return accuracy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:25:11,683 - INFO - 训练并评估逻辑回归模型...\n",
      "c:\\Users\\29242\\.conda\\envs\\py38\\lib\\site-packages\\sklearn\\linear_model\\_logistic.py:460: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n",
      "2024-10-31 19:25:12,996 - INFO - logistic_regression模型训练完成。用时1.3119秒。\n",
      "2024-10-31 19:25:13,010 - INFO - logistic_regression模型评估完成。用时0.0120秒。\n",
      "2024-10-31 19:25:13,010 - INFO - logistic_regression模型准确率: 0.5392\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估逻辑回归模型\n",
    "logistic_model = LogisticRegression()\n",
    "logging.info(\"训练并评估逻辑回归模型...\")\n",
    "logistic_accuracy = train_and_evaluate(logistic_model, \"logistic_regression\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:25:18,067 - INFO - 训练并评估随机森林模型...\n",
      "2024-10-31 19:26:35,103 - INFO - random_forest模型训练完成。用时77.0363秒。\n",
      "2024-10-31 19:26:35,302 - INFO - random_forest模型评估完成。用时0.1971秒。\n",
      "2024-10-31 19:26:35,303 - INFO - random_forest模型准确率: 0.6381\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估随机森林模型\n",
    "rf_model = RandomForestClassifier(n_estimators=100, random_state=2023)\n",
    "logging.info(\"训练并评估随机森林模型...\")\n",
    "rf_accuracy = train_and_evaluate(rf_model, \"random_forest\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:26:42,214 - INFO - 训练并评估SVM模型...\n",
      "2024-10-31 19:30:25,868 - INFO - svm模型训练完成。用时223.6545秒。\n",
      "2024-10-31 19:31:38,837 - INFO - svm模型评估完成。用时72.9675秒。\n",
      "2024-10-31 19:31:38,838 - INFO - svm模型准确率: 0.6624\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估SVM模型\n",
    "svm_model = SVC(gamma='scale')\n",
    "logging.info(\"训练并评估SVM模型...\")\n",
    "svm_accuracy = train_and_evaluate(svm_model, \"svm\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:32:04,108 - INFO - 训练并评估软投票模型...\n",
      "2024-10-31 19:51:00,887 - INFO - soft_voting模型训练完成。用时1136.7779秒。\n",
      "2024-10-31 19:52:11,231 - INFO - soft_voting模型评估完成。用时70.3427秒。\n",
      "2024-10-31 19:52:11,232 - INFO - soft_voting模型准确率: 0.6550\n"
     ]
    }
   ],
   "source": [
    "from sklearn.ensemble import VotingClassifier\n",
    "logistic_clf = LogisticRegression()\n",
    "random_forest_clf = RandomForestClassifier(random_state=42)\n",
    "svm_clf = SVC(probability=True)\n",
    "voting_clf_soft = VotingClassifier(\n",
    "    estimators=[('lr', logistic_clf), ('rf', random_forest_clf), ('svc', svm_clf)],\n",
    "    voting='soft',  \n",
    "    weights=[1, 1, 2],  \n",
    "    n_jobs=-1  \n",
    ")\n",
    "\n",
    "logging.info(\"训练并评估软投票模型...\")\n",
    "soft_voting_accuracy = train_and_evaluate(voting_clf_soft, \"soft_voting\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:53:41,462 - INFO - 训练并评估硬投票模型...\n",
      "2024-10-31 19:57:32,503 - INFO - hard_voting模型训练完成。用时231.0389秒。\n",
      "2024-10-31 19:58:48,708 - INFO - hard_voting模型评估完成。用时76.2035秒。\n",
      "2024-10-31 19:58:48,708 - INFO - hard_voting模型准确率: 0.6384\n"
     ]
    }
   ],
   "source": [
    "logistic_clf = LogisticRegression()\n",
    "random_forest_clf = RandomForestClassifier(random_state=42)\n",
    "svm_clf = SVC()\n",
    "hard_voting_clf = VotingClassifier(\n",
    "   estimators=[\n",
    "       ('lr', logistic_clf),  # 逻辑回归\n",
    "       ('rf', random_forest_clf),  # 随机森林\n",
    "       ('svc', svm_clf)  # 支持向量机\n",
    "   ],\n",
    "   voting='hard',  # 使用硬投票\n",
    "   weights=[1, 2, 1],  # 为随机森林分类器设置更高权重(2),其他分类器权重为1\n",
    "   n_jobs=-1  # 使用所有CPU核心\n",
    ")\n",
    "logging.info(\"训练并评估硬投票模型...\")\n",
    "hard_voting_accuracy = train_and_evaluate(hard_voting_clf, \"hard_voting\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 19:59:00,395 - INFO - 训练并评估装袋模型...\n",
      "2024-10-31 20:00:18,989 - INFO - bagging模型训练完成。用时78.5926秒。\n",
      "2024-10-31 20:00:19,193 - INFO - bagging模型评估完成。用时0.2022秒。\n",
      "2024-10-31 20:00:19,194 - INFO - bagging模型准确率: 0.6381\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估装袋模型\n",
    "bagging_model = RandomForestClassifier(n_estimators=100, random_state=2023, bootstrap=True)\n",
    "logging.info(\"训练并评估装袋模型...\")\n",
    "bagging_accuracy = train_and_evaluate(bagging_model, \"bagging\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 20:00:26,200 - INFO - 训练并评估粘贴模型...\n",
      "2024-10-31 20:00:26,202 - INFO - pasting模型训练完成。用时0.0010秒。\n",
      "2024-10-31 20:00:28,725 - INFO - pasting模型评估完成。用时2.5220秒。\n",
      "2024-10-31 20:00:28,726 - INFO - pasting模型准确率: 0.5645\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估粘贴模型\n",
    "pasting_model = KNeighborsClassifier()\n",
    "logging.info(\"训练并评估粘贴模型...\")\n",
    "pasting_accuracy = train_and_evaluate(pasting_model, \"pasting\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 20:01:42,302 - INFO - 训练并评估adaboost模型...\n",
      "2024-10-31 20:03:12,845 - INFO - adaboost模型训练完成。用时90.5421秒。\n",
      "2024-10-31 20:03:13,827 - INFO - adaboost模型评估完成。用时0.9814秒。\n",
      "2024-10-31 20:03:13,829 - INFO - adaboost模型准确率: 0.5739\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估adaboost模型\n",
    "adaboost_model = AdaBoostClassifier(n_estimators=100, random_state=2023)\n",
    "logging.info(\"训练并评估adaboost模型...\")\n",
    "adaboost_accuracy = train_and_evaluate(adaboost_model, \"adaboost\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 20:03:17,996 - INFO - 训练并评估gradient_boost模型...\n",
      "2024-10-31 20:07:47,381 - INFO - gradient_boosting模型训练完成。用时269.3832秒。\n",
      "2024-10-31 20:07:47,418 - INFO - gradient_boosting模型评估完成。用时0.0354秒。\n",
      "2024-10-31 20:07:47,418 - INFO - gradient_boosting模型准确率: 0.6318\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估gradient_boost模型\n",
    "gradient_boost_model = GradientBoostingClassifier(n_estimators=100, random_state=2023)\n",
    "logging.info(\"训练并评估gradient_boost模型...\")\n",
    "gradient_boost_accuracy = train_and_evaluate(gradient_boost_model, \"gradient_boosting\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 20:08:55,749 - INFO - 训练并评估堆叠模型...\n",
      "2024-10-31 20:14:06,558 - INFO - stacking模型训练完成。用时310.8084秒。\n",
      "2024-10-31 20:14:08,968 - INFO - stacking模型评估完成。用时2.4092秒。\n",
      "2024-10-31 20:14:08,969 - INFO - stacking模型准确率: 0.6366\n"
     ]
    }
   ],
   "source": [
    "# 训练和评估堆叠模型\n",
    "stack_model = StackingClassifier(estimators=[('knn', KNeighborsClassifier()), ('rf', RandomForestClassifier())], final_estimator=LogisticRegression(), n_jobs=-1)\n",
    "logging.info(\"训练并评估堆叠模型...\")\n",
    "stack_accuracy = train_and_evaluate(stack_model, \"stacking\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2024-10-31 20:14:50,679 - INFO - 模型已保存为 best_model.pkl\n"
     ]
    }
   ],
   "source": [
    "# 将最佳模型保存为pickle文件\n",
    "def save_model(model, filename=\"best_model.pkl\"):\n",
    "    with open(filename, \"wb\") as f:\n",
    "        pickle.dump(model, f)\n",
    "    logging.info(f\"模型已保存为 {filename}\")\n",
    "\n",
    "# 保存最佳模型\n",
    "# 这里可以根据准确率选择最佳模型进行保存，示例中以逻辑回归模型为例\n",
    "save_model(logistic_model)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "py38",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.20"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
